package com.joymart.compute.service;

import com.joymart.common.model.Range;
import com.joymart.common.system.IdGenerator;
import com.joymart.common.utils.DatetimeUtils;
import com.joymart.compute.model.MonthlyGroupPv;
import com.joymart.compute.repository.MonthlyGroupPvRepository;
import com.joymart.user.model.BusinessRole;
import com.joymart.user.model.CachedUser;
import com.joymart.user.repo.UserRepository;
import com.joymart.user.service.UserCacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class MonthlyGroupPvService {

    @Autowired
    private SalesPvService salesPvService;
    @Autowired
    private IdGenerator idGenerator;
    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private MonthlyGroupPvRepository monthlyGroupPvRepository;
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private JdbcAggregateTemplate jdbcAggregateTemplate;


    public List<MonthlyGroupPv> findMonthlyGroupPv(CachedUser user, BusinessRole scale, Range range) {
        return monthlyGroupPvRepository.findMonthlyGroupPv(user.getId(), scale, range.getStart(),range.getEnd());
    }

    public long countMonthlyGroupPvGreaterThan(CachedUser user, BusinessRole scale,  Range range, BigDecimal spec) {
        return monthlyGroupPvRepository.countMonthlyGroupPvGreaterThan(user.getId(), scale, range.getStart(),range.getEnd(), spec);
    }

    public void computeMonthlyGroupPv(LocalDateTime month, BusinessRole scale) {
        List<MonthlyGroupPv> batch = new ArrayList<>();
        Range range = DatetimeUtils.month(month);
        monthlyGroupPvRepository.deleteAllBetween(scale, range.getStart(), range.getEnd());

        userRepository.findInitialNonPartyAUsers()
                .stream().map(userCacheManager::get).forEach(user -> {
            recursiveComputeMonthlyGroupPv(user, range, scale, batch, null);
        });

        jdbcAggregateTemplate.insertAll(batch);
    }

    public void recursiveComputeMonthlyGroupPv(
            CachedUser user,
            Range range,
            BusinessRole scale,
            List<MonthlyGroupPv> batch,
            @Nullable MonthlyGroupPv container
            ) {
        if(user.getBusinessRoles().contains(scale)) {
            container = createNewRecursingPoint(user, range, scale, batch);
        }
        mergeSalesPv(user.getId(), range, container);

        final MonthlyGroupPv _container = container; //编译器要求 lambda里面的变量为final的

        user.getDownstreamIds().stream().map(userCacheManager::get).forEach(downstreamUser -> {
            recursiveComputeMonthlyGroupPv(downstreamUser, range, scale, batch, _container);
        });

    }

    private void mergeSalesPv(String id, Range range, MonthlyGroupPv current) {
        if(current == null) return;
        BigDecimal salesPv = salesPvService.getSalesPv(id,range);
        current.setAmount(current.getAmount().add(salesPv, MathContext.DECIMAL64));
    }

    private MonthlyGroupPv createNewRecursingPoint(CachedUser user, Range range, BusinessRole scale, List<MonthlyGroupPv> batch) {
        MonthlyGroupPv monthlyGroupPv = new MonthlyGroupPv();
        monthlyGroupPv.setId(idGenerator.next());
        monthlyGroupPv.setAmount(BigDecimal.ZERO);
        monthlyGroupPv.setScale(scale);
        monthlyGroupPv.setMonth(range.getStart());
        monthlyGroupPv.setCreatedAt(DatetimeUtils.now());
        monthlyGroupPv.setUserId(user.getId());
        batch.add(monthlyGroupPv);
        return monthlyGroupPv;
    }


}
